<template>
  <!-- 这里改回scroll-view，监听scroll事件 -->
  <scroll-view
    scroll-y
    id="contentRef"
    class="fs-virtual-waterfall-container"
    :style="{ height: '100vh' }"
    @scroll="handleScroll"
  >
    <div class="fs-virtual-waterfall-content">
      <!-- 修改容器的 style -->
      <div class="fs-virtual-waterfall-list" :style="contentStyleStr">
        <div
          class="fs-virtual-waterfall-item"
          v-for="render in renderListStr"
          :key="render.item.id"
          :style="render.styleStr"
        >
          <!-- <slot name="item" :item="render.item"></slot> -->
          <image
            v-if="render.item.src"
            :src="render.item.src"
            class="test-item"
            :style="{ width: render.style.width, height: render.style.height }"
            mode="scaleToFill"
          />
          <div class="bottom">
            <div class="item-text">{{ render.item.addressDescription }}</div>
            <div class="info">
              <div class="name">{{ render.item.author.username }}</div>
              <div class="love">
                {{ render.item.favoriteCount }}
                <uni-icons type="heart" size="17"></uni-icons>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </scroll-view>
</template>

<script>
import { debounce, rafThrottle } from "./tool"; // 导入防抖/节流工具函数

export default {
  name: "FsVirtualWaterFall",
  props: {
    request: {
      // 数据请求函数
      type: Function,
      default: async () => ({ list: [], total: 0 }),
    },
    gap: {
      // 瀑布流列间距
      type: Number,
      default: 10,
    },
    column: {
      // 瀑布流列数
      type: Number,
      default: 2,
    },
    columnItemCount: {
      // 每列初始加载的 item 数量
      type: Number,
      default: 3,
    },
    requestSize: {
      // 每次请求数据的数量
      type: Number,
      default: 20,
    },
  },
  data() {
    return {
      dataState: {
        loading: false, // 是否加载中
        isFinish: false, // 是否加载完所有数据
        currtentPage: 1, // 当前页码
        total: 0, // 总数
        list: [], // 全部数据列表
      },
      columnState: {
        queue: [], // 每一列的数据及其高度
        len: 0, // 已经渲染的数据数量
      },
      scrollState: {
        viewHeight: 0, // 可视区域高度
        viewWidth: 0, // 可视区域宽度
        start: 0, // 当前滚动条滚动位置（顶部）
      },
    };
  },
  computed: {
    contentStyleStr() {
      return this.getStyle(this.contentStyle);
    },
    renderListStr() {
      let a = this.renderList.map((i) => ({
        ...i,
        styleStr: this.getStyle(i.style),
      }));
      console.log("bug:", a);
      return a;
    },
    // 可视区域底部位置
    end() {
      return this.scrollState.start + this.scrollState.viewHeight;
    },
    // 所有 item 的尺寸信息 Map（以 id 为 key）
    itemSizeInfo() {
      const map = new Map();
      const itemWidth = Math.floor(
        (this.scrollState.viewWidth - (this.column - 1) * this.gap) / this.column
      );
      this.dataState.list.forEach((item) => {
        console.log("test：", item.height);
        map.set(item.id, {
          width: itemWidth,
          height: Math.floor((itemWidth * item.height) / item.width), // 按比例计算高度
        });
      });
      console.log("map", map);
      return map;
    },
    // 计算当前各列的最大最小高度等信息
    computedHeight() {
      let minIndex = 0,
        maxIndex = 0,
        minHeight = Infinity,
        maxHeight = -Infinity;
      this.columnState.queue.forEach(({ height }, index) => {
        if (height <= minHeight) {
          minHeight = height;
          minIndex = index;
        }
        if (height >= maxHeight) {
          maxHeight = height;
          maxIndex = index;
        }
      });
      return { minIndex, maxIndex, minHeight, maxHeight };
    },
    // 容器总高度（等于最高列高度）
    contentStyle() {
      return {
        height: `${this.computedHeight.maxHeight}px`,
      };
    },
    // 是否还有未渲染的数据
    hasMoreData() {
      return this.columnState.len < this.dataState.list.length;
    },
    // 所有列展开成一维数组后的完整 item 列表
    columnList() {
      console.log(this.columnState.queue);
      return this.columnState.queue.reduce(
        (pre, current) => pre.concat(current.list),
        []
      );
    },
    // 当前需要渲染在视口内的 item（做虚拟滚动）
    renderList() {
      let arr = this.columnList.filter((i) => {
        return i.h + i.y > this.scrollState.start && i.y < this.end;
      });
      console.log(this.columnList);
      console.log("arr", arr);
      return arr;
    },

    // 实际请求数量：若传了 requestSize 就用它，否则根据列数和列内 item 数量计算
    realRequestSize() {
      return this.requestSize || this.column * this.columnItemCount;
    },
  },
  methods: {
    getStyle(styleObj) {
      if (!styleObj || typeof styleObj !== "object") return "";
      const updatedStyle = { ...styleObj };
      if (updatedStyle.height) {
        const mach = String(updatedStyle.height).match(/^(\d+)(px)?$/);
        if (mach) {
          const newHeight = parseInt(mach[1]) + 55;
          updatedStyle.height = `${newHeight}px`;
        }
      }

      const obj = Object.entries(updatedStyle)
        .map(([key, value]) => `${key}:${value}`)
        .join(";");

      console.log("样式：", obj);
      return obj;
    },
    // 加载数据列表
    async loadDataList() {
      if (this.dataState.isFinish) return;
      this.dataState.loading = true;
      const { list, total } = await this.request(
        this.dataState.currtentPage++,
        this.realRequestSize
      );

      // 若无更多数据，则标记完成
      if (!list.length) {
        this.dataState.isFinish = true;
        this.$emit("finishLoadData");
        return;
      }

      // 处理 item 的图片信息
      const processedList = list.map((item) => {
        if (item.image) {
          item.src = item.image.src;
          item.width = item.image.width;
          item.height = item.image.height;
        }
        return item;
      });

      // 添加到数据列表中
      this.dataState.list.push(...processedList);
      this.dataState.total = total;
      this.dataState.loading = false;
    },
    // 生成每个 item 的定位信息
    generatorItem(item, before, index) {
      const rect = this.itemSizeInfo.get(item.id);
      const width = rect?.width || 0;
      const height = rect?.height || 0;
      let y = 0;
      if (before) y = before.y + before.h + this.gap + 55; // 上一个 item 的 y + h + gap
      let gItem = {
        item,
        y,
        h: height,
        style: JSON.parse(
          JSON.stringify({
            width: `${width}px`,
            height: `${height}px`,
            transform: `translate3d(${index * (width + this.gap)}px, ${y}px, 0)`,
          })
        ),
      };
      console.log("gItgem", gItem);
      return gItem;
    },
    // 把 item 加入到列中（每次添加一个）
    addInQueue(size = Math.floor(this.column)) {
      for (let i = 0; i < size; i++) {
        if (!this.hasMoreData) return;
        const dataItem = this.dataState.list[this.columnState.len];
        const minIndex = this.computedHeight.minIndex; // 找最矮的一列
        const currentQueue = this.columnState.queue[minIndex];
        const before = currentQueue.list[currentQueue.list.length - 1] || null;
        const genItem = this.generatorItem(dataItem, before, minIndex);
        currentQueue.list.push(genItem);
        currentQueue.height += genItem.h;
        this.columnState.len++;
      }
    },
    // 根据 item 重排所有列的位置（用于 resize）
    reComputedColumn() {
      this.columnState.queue = this.columnState.queue.map((q, index) => {
        let height = 0;
        const list = q.list.reduce((pre, { item }, i) => {
          const before = pre[i - 1] || null;
          const result = this.generatorItem(item, before, index);
          height += result.h;
          pre.push(result);
          return pre;
        }, []);
        return { height, list };
      });
    },
    // 初始化滚动区域尺寸
    initSrollState() {
      return new Promise((resolve) => {
        uni
          .createSelectorQuery()
          .in(this)
          .select("#contentRef") // 选择 scroll-view 容器
          .boundingClientRect((rect) => {
            if (rect) {
              this.scrollState.viewWidth = rect.width || 0;
              this.scrollState.viewHeight = rect.height || 0;
            }
            resolve();
          })
          .exec();
      });
    },
    // 初始化：获取尺寸 + 加载数据 + 初始化列布局
    async init() {
      await this.initSrollState();
      await this.loadDataList();
      this.addInQueue(this.realRequestSize);
    },
    
    handleScroll(e) {
      // 微信小程序 scroll-view 事件的 scrollTop 在 e.detail
      const scrollTop = e.detail.scrollTop;
      // 若未加载中 && 有剩余数据
      if (!this.dataState.loading && this.hasMoreData) {
         this.addInQueue();
      }

      // 滚动到底部附近，触发加载更多
      if (scrollTop + this.scrollState.viewHeight > this.computedHeight.maxHeight) {
      
         this.loadDataList().then(() => {
          this.addInQueue();
        });
      }
    },

    // 处理窗口尺寸变化（重新计算容器高度与布局）
    handleResize: debounce(function () {
      this.initSrollState();
      this.reComputedColumn();
    }, 300),
  },
  mounted() {
    // 初始化列结构
    this.columnState.queue = Array(this.column)
      .fill(0)
      .map(() => ({ list: [], height: 0 }));
    this.init();

    // 监听页面尺寸变化（H5端）
    uni.onWindowResize && uni.onWindowResize(this.handleResize);
  },
  beforeDestroy() {
    // 移除监听
    if (uni.offWindowResize) uni.offWindowResize(this.handleResize);
  },
};
</script>

<style lang="scss">
.fs-virtual-waterfall {
  &-container {
    width: 100%;
    // height: 100%;
    /* 改为可滚动容器 */
    overflow-y: auto;
  }

  &-content {
    width: 100%;
    height: 100%;
    // overflow-y: scroll;
  }

  &-list {
    position: relative;
    width: 100%;
    height: 100%;
  }

  &-item {
    position: absolute;
    top: 0;
    left: 0;
    transition: all 0.3s;
    box-sizing: border-box;

    background-color: #fff;
    border-radius: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    overflow: hidden;
    .test-item {
      width: 100%;
      display: block;
    }
    .bottom {
      padding: 5px 5px;
      .item-text {
        font-size: 14px;
        color: black;
        word-break: break-word;
      }
      .info {
        display: flex;
        justify-content: space-between;
        align-items: center;
        .love {
          display: flex;
          align-items: center;
        }
      }
    }
  }
}
</style>
